Explore Method Dispatch in this in-depth article.
- What is Method Dispatch
- Type 1: Static Dispatch (Direct Dispatch)
- Type 2: Dynamic Dispatch (Table Dispatch)
- Type 3: Message Dispatch
- Method Dispatch Usage And Examples
- Increasing Performance by Reducing Dynamic Dispatch
- References
Method Dispatch:
- It is a mechanism used in object-oriented languages.
- When invoking a method it is an algorithm that selects which instructions (method) to execute.
- Tells your app where to find the method in memory before it gets executed.
- It's something that happens every time a method is called.
- How it works when invoking a method:
- The compiler knows the memory address of the invoked method at compile time.
- The method is executed directly.
- Result of this mechanism:
- The fastest method dispatch style.
- Enables various compiler optimizations (e.g., devirtualization).
- Devirtualization: A compilation phase where the compiler attempts to make functions static when applicable.
- Used by:
- Value types.
- Imposes restrictions on inheritance (the method cannot be overridden).
- Extensions.
- Reference types marked with the
finalkeyword. - Methods and classes marked with
privateandstatic.
- Value types.
- How it works when invoking a method:
- The compiler doesn't know the memory address of the invoked method at compile time.
- The compiler creates a table with function pointers for each class (known as the witness table or the virtual table).
- At runtime, when the method is invoked, memory address of a method is searched in that table.
- Then the method is executed. So the method is executed indirectly.
- Result of this mechanism:
- Slower than the Static Dispatch.
- This prevent many compiler optimizations, making the indirect call even more expensive.
- How the virtual table is constructed for a subclass:
- A subclass copies the table with a function pointers from the parent class.
- There are different function pointer for every method that the class has overridden.
- New methods in the subclass are appended to the end of this array.
- Used by:
- Reference types without
finalkeyword. - Protocols.
- Methods marked with
dynamickeyword.
- Reference types without
- Utilized in Objective-C to provide this mechanism.
- How it works when invoking a method:
- Works similarly to Dynamic Dispatch.
- Additionally, allows us to change which method is called at runtime.
- Result of this mechanism:
- The slowest among all Dispatch Methods.
- Commonly used for:
- Method Swizzling.
- Functions marked with the
dynamickeyword. - Functions marked with the
@objckeyword.
- Facilitates altering the dispatch behavior at runtime.
| Initial Declaration | Extension | |
|---|---|---|
| Value Type | Static | Static |
| Reference Type | Table (even for @objc) |
Static / Message (for @objc) |
| Protocols | Table | Static |
| NSObject subclass | Table | Message |
protocol Noisy {
func makeNoise() -> Int // Protocol: Initial Declaration => TABLE
}
extension Noisy {
func makeNoise() -> Int { return 0 } // TABLE (Inherited from the protocol (?))
func isAnnoying() -> Bool { return true } // Protocol: Extension => STATIC
}
class Animal: Noisy {
func makeNoise() -> Int { return 1 } // Reference Type => TABLE
func isAnnoying() -> Bool { return false } // Reference Type => TABLE
@objc func sleep() { } // Reference Type => TABLE
}
extension Animal {
func eat() { } // STATIC
@objc func getWild() { } // MESSAGE
}-
Use the
finalkeyword: the declaration cannot be overridden. -
Use the
privateaccess modifier:
- Restricts the visibility of the declaration to the current file.
- Enables the compiler to infer the final keyword.
- Use Whole Module Optimization:
- All of the module is compiled together at the same time.
- This allows the compiler to infer
finalon declarations withinternal.